"""
HTTP客户端模块
HTTP Client Module
"""

import requests
import time
import json
import logging
from typing import Dict, Any, Optional
from urllib.parse import urljoin
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry


class HttpClientError(Exception):
    """HTTP客户端异常"""
    pass


class RateLimitError(HttpClientError):
    """请求频率限制异常"""
    pass


class HttpClient:
    """HTTP客户端类"""
    
    def __init__(self, config_manager):
        """初始化HTTP客户端"""
        self.config = config_manager
        self.logger = logging.getLogger(__name__)
        
        # 创建会话
        self.session = requests.Session()
        
        # 设置默认headers
        headers = self.config.get_headers()
        self.session.headers.update(headers)
        
        # 请求配置
        self.delay = self.config.get_request_delay()
        self.timeout = self.config.get_request_timeout()
        self.retry_times = self.config.get_retry_times()
        
        # 设置连接池和重试策略
        self._setup_session()
        
        # 请求统计
        self.stats = {
            'total_requests': 0,
            'successful_requests': 0,
            'failed_requests': 0,
            'retry_count': 0
        }
        
        # 最后请求时间，用于频率控制
        self.last_request_time = 0
    
    def _setup_session(self):
        """设置会话配置"""
        # 配置重试策略
        retry_strategy = Retry(
            total=self.retry_times,
            status_forcelist=[429, 500, 502, 503, 504],
            allowed_methods=["HEAD", "GET", "OPTIONS"],
            backoff_factor=1
        )
        
        # 配置HTTP适配器
        adapter = HTTPAdapter(max_retries=retry_strategy)
        self.session.mount("http://", adapter)
        self.session.mount("https://", adapter)
    
    def get_page_data(self, city: str, business_type: str, page: int = 1) -> Dict[str, Any]:
        """获取页面数据"""
        if not self.config.validate_city(city):
            raise HttpClientError(f"Invalid city: {city}")
        
        if not self.config.validate_business_type(business_type):
            raise HttpClientError(f"Invalid business type: {business_type}")
        
        url = self._build_url(city, business_type, page)
        self.logger.info(f"Fetching data from: {url}")
        
        for attempt in range(self.retry_times + 1):
            try:
                response = self._make_request(url)
                result = self._handle_response(response)
                
                self.stats['successful_requests'] += 1
                self.logger.debug(f"Successfully fetched data from {url}")
                
                return result
                
            except requests.exceptions.RequestException as e:
                self.stats['retry_count'] += 1
                self.logger.warning(f"Request failed (attempt {attempt + 1}/{self.retry_times + 1}): {e}")
                
                if attempt == self.retry_times:
                    self.stats['failed_requests'] += 1
                    self.logger.error(f"All retry attempts failed for {url}")
                    raise HttpClientError(f"Failed to fetch data after {self.retry_times + 1} attempts: {e}")
                
                # 指数退避
                wait_time = self.delay * (2 ** attempt)
                self.logger.info(f"Waiting {wait_time} seconds before retry...")
                time.sleep(wait_time)
            
            except Exception as e:
                self.stats['failed_requests'] += 1
                self.logger.error(f"Unexpected error fetching {url}: {e}")
                raise HttpClientError(f"Unexpected error: {e}")
        
        return {}
    
    def _build_url(self, city: str, business_type: str, page: int) -> str:
        """构建请求URL"""
        business_code = self.config.get_business_type_code(business_type)
        base_url = f"https://{city}.puxiansheng.com/find_list-{business_code}.html"
        
        if page > 1:
            base_url += f"?page={page}"
        
        return base_url
    
    def _make_request(self, url: str) -> requests.Response:
        """发送HTTP请求"""
        # 实现请求频率限制
        self._enforce_rate_limit()
        
        self.stats['total_requests'] += 1
        
        try:
            response = self.session.get(url, timeout=self.timeout)
            
            # 检查响应状态
            if response.status_code == 429:
                raise RateLimitError("Rate limit exceeded")
            
            response.raise_for_status()
            
            # 更新最后请求时间
            self.last_request_time = time.time()
            
            return response
            
        except requests.exceptions.Timeout:
            self.logger.error(f"Request timeout for {url}")
            raise
        except requests.exceptions.ConnectionError:
            self.logger.error(f"Connection error for {url}")
            raise
        except requests.exceptions.HTTPError as e:
            self.logger.error(f"HTTP error {e.response.status_code} for {url}")
            raise
        except Exception as e:
            self.logger.error(f"Unexpected error making request to {url}: {e}")
            raise
    
    def _enforce_rate_limit(self):
        """实现请求频率限制"""
        if self.last_request_time > 0:
            elapsed = time.time() - self.last_request_time
            if elapsed < self.delay:
                sleep_time = self.delay - elapsed
                self.logger.debug(f"Rate limiting: sleeping for {sleep_time:.2f} seconds")
                time.sleep(sleep_time)
    
    def _handle_response(self, response: requests.Response) -> Dict[str, Any]:
        """处理响应数据"""
        try:
            # 尝试解析JSON响应
            data = response.json()
            self.logger.debug(f"Successfully parsed JSON response with {len(str(data))} characters")
            return data
        except json.JSONDecodeError as e:
            self.logger.warning(f"Failed to parse JSON response: {e}")
            # 如果不是JSON，返回HTML内容
            return {
                'html': response.text,
                'status_code': response.status_code,
                'content_type': response.headers.get('content-type', 'unknown')
            }
    
    def get_stats(self) -> Dict[str, Any]:
        """获取请求统计信息"""
        return self.stats.copy()
    
    def reset_stats(self):
        """重置统计信息"""
        self.stats = {
            'total_requests': 0,
            'successful_requests': 0,
            'failed_requests': 0,
            'retry_count': 0
        }
        self.logger.info("HTTP client statistics reset")
    
    def get_success_rate(self) -> float:
        """获取请求成功率"""
        if self.stats['total_requests'] == 0:
            return 0.0
        return self.stats['successful_requests'] / self.stats['total_requests']
    
    def is_healthy(self) -> bool:
        """检查客户端健康状态"""
        # 如果成功率低于50%，认为不健康
        return self.get_success_rate() >= 0.5 or self.stats['total_requests'] < 10
    
    def close(self):
        """关闭会话"""
        self.logger.info("Closing HTTP client session")
        self.session.close()